#!/usr/bin/env node

import http from 'http';
import https from 'https';
import { promises as fs } from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
import os from 'os';
import dotenv from 'dotenv';

// Get __dirname equivalent in ES modules
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

// Load environment variables from .env file
dotenv.config({ path: path.join(__dirname, '.env') });

// Version information
const VERSION = '2.0.0';
const PORT = process.env.SHRIMP_VIEWER_PORT || 9998;
const SETTINGS_FILE = path.join(os.homedir(), '.shrimp-task-viewer-settings.json');
const GLOBAL_SETTINGS_FILE = path.join(os.homedir(), '.shrimp-task-viewer-global-settings.json');
const TEMPLATES_DIR = path.join(os.homedir(), '.shrimp-task-viewer-templates');
const PROJECT_ROOT = path.join(__dirname, '..', '..');
const DEFAULT_TEMPLATES_DIR = path.join(PROJECT_ROOT, 'src', 'prompts', 'templates_en');

// Helper function to get ISO string in local timezone format
function getLocalISOString() {
  const now = new Date();
  const year = now.getFullYear();
  const month = String(now.getMonth() + 1).padStart(2, '0');
  const day = String(now.getDate()).padStart(2, '0');
  const hours = String(now.getHours()).padStart(2, '0');
  const minutes = String(now.getMinutes()).padStart(2, '0');
  const seconds = String(now.getSeconds()).padStart(2, '0');
  
  // Get timezone offset in hours and minutes
  const offset = -now.getTimezoneOffset();
  const offsetHours = String(Math.floor(Math.abs(offset) / 60)).padStart(2, '0');
  const offsetMinutes = String(Math.abs(offset) % 60).padStart(2, '0');
  const offsetSign = offset >= 0 ? '+' : '-';
  
  return `${year}-${month}-${day}T${hours}:${minutes}:${seconds}${offsetSign}${offsetHours}:${offsetMinutes}`;
}

// Default agent data paths configuration
const defaultAgents = [];

let projects = []; // Project list

// Parse YAML frontmatter from agent file content
function parseAgentMetadata(content) {
    const metadata = {
        name: '',
        description: '',
        tools: [],
        color: null
    };
    
    if (!content) return metadata;
    
    // Check if content starts with YAML frontmatter
    const frontmatterRegex = /^---\s*\n([\s\S]*?)\n---\s*\n/;
    const match = content.match(frontmatterRegex);
    
    if (match) {
        const yamlContent = match[1];
        // Improved YAML parsing for the fields we need
        const lines = yamlContent.split('\n');
        
        let currentField = null;
        let multilineValue = [];
        
        for (let i = 0; i < lines.length; i++) {
            const line = lines[i];
            const trimmedLine = line.trim();
            
            // Check if this is a field definition
            if (trimmedLine.includes(':') && !line.startsWith('  ')) {
                // Save any previous multiline field
                if (currentField === 'description' && multilineValue.length > 0) {
                    metadata.description = multilineValue.join(' ').trim().replace(/^["']|["']$/g, '');
                    multilineValue = [];
                }
                
                if (trimmedLine.startsWith('name:')) {
                    currentField = 'name';
                    metadata.name = trimmedLine.substring(5).trim().replace(/^["']|["']$/g, '');
                } else if (trimmedLine.startsWith('description:')) {
                    currentField = 'description';
                    const value = trimmedLine.substring(12).trim();
                    if (value) {
                        metadata.description = value.replace(/^["']|["']$/g, '');
                    }
                } else if (trimmedLine.startsWith('tools:')) {
                    currentField = 'tools';
                    const toolsStr = trimmedLine.substring(6).trim();
                    if (toolsStr && !toolsStr.startsWith('[')) {
                        // Single line tools
                        metadata.tools = toolsStr.split(',').map(t => t.trim()).filter(t => t.length > 0);
                    }
                } else if (trimmedLine.startsWith('color:')) {
                    currentField = 'color';
                    metadata.color = trimmedLine.substring(6).trim().replace(/^["']|["']$/g, '');
                } else {
                    currentField = null;
                }
            } else if (currentField === 'description' && trimmedLine && trimmedLine !== '-') {
                // Multiline description
                multilineValue.push(trimmedLine.replace(/^-\s*/, ''));
            } else if (currentField === 'tools' && trimmedLine.startsWith('-')) {
                // Array format tools
                if (!metadata.tools) metadata.tools = [];
                metadata.tools.push(trimmedLine.substring(1).trim());
            }
        }
        
        // Handle any remaining multiline field
        if (currentField === 'description' && multilineValue.length > 0) {
            metadata.description = multilineValue.join(' ').trim().replace(/^["']|["']$/g, '');
        }
    }
    
    return metadata;
}

// Load or create settings file
async function loadSettings() {
    try {
        console.log('Loading settings from:', SETTINGS_FILE);
        const data = await fs.readFile(SETTINGS_FILE, 'utf8');
        const settings = JSON.parse(data);
        console.log('Loaded settings:', settings);
        return settings.projects || settings.profiles || settings.agents || []; // Support new 'projects' and old keys for backward compatibility
    } catch (err) {
        console.error('Error loading settings:', err.message);
        await saveSettings(defaultAgents);
        return defaultAgents;
    }
}

// Save settings file
async function saveSettings(projectList) {
    const settings = {
        projects: projectList, // Changed from 'agents' to 'projects' for clarity
        lastUpdated: getLocalISOString(),
        version: VERSION
    };
    await fs.writeFile(SETTINGS_FILE, JSON.stringify(settings, null, 2));
}

// Load or create global settings file
async function loadGlobalSettings() {
    try {
        console.log('Loading global settings from:', GLOBAL_SETTINGS_FILE);
        const data = await fs.readFile(GLOBAL_SETTINGS_FILE, 'utf8');
        const settings = JSON.parse(data);
        console.log('Loaded global settings:', settings);
        return settings;
    } catch (err) {
        console.error('Error loading global settings:', err.message);
        const defaultGlobalSettings = {
            claudeFolderPath: '',
            lastUpdated: getLocalISOString(),
            version: VERSION
        };
        await saveGlobalSettings(defaultGlobalSettings);
        return defaultGlobalSettings;
    }
}

// Save global settings file
async function saveGlobalSettings(settings) {
    await fs.writeFile(GLOBAL_SETTINGS_FILE, JSON.stringify(settings, null, 2));
}

// Add new project
async function addProject(name, filePath, projectRoot = null) {
    const id = name.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-');
    const newProfile = { id, name, path: filePath, projectRoot };
    
    const existingIndex = projects.findIndex(p => p.id === id);
    if (existingIndex >= 0) {
        projects[existingIndex] = newProfile;
    } else {
        projects.push(newProfile);
    }
    
    await saveSettings(projects);
    return newProfile;
}

// Remove project
async function removeProject(projectId) {
    projects = projects.filter(p => p.id !== projectId);
    await saveSettings(projects);
}

// Rename agent
async function renameProject(projectId, newName) {
    const project = projects.find(p => p.id === projectId);
    if (!project) {
        throw new Error('Project not found');
    }
    project.name = newName;
    await saveSettings(projects);
    return project;
}

async function updateProject(projectId, updates) {
    const project = projects.find(p => p.id === projectId);
    if (!project) {
        throw new Error('Project not found');
    }
    
    // Apply updates
    if (updates.name !== undefined) {
        project.name = updates.name;
    }
    if (updates.projectRoot !== undefined) {
        project.projectRoot = updates.projectRoot;
    }
    if (updates.taskPath !== undefined) {
        // Update the path property (which is what the project actually uses)
        project.path = updates.taskPath;
        // Also update taskPath and filePath for consistency
        project.taskPath = updates.taskPath;
        project.filePath = updates.taskPath;
    }
    
    await saveSettings(projects);
    return project;
}

// MIME type helper
function getMimeType(filePath) {
    const ext = path.extname(filePath).toLowerCase();
    const mimeTypes = {
        '.html': 'text/html',
        '.js': 'application/javascript',
        '.css': 'text/css',
        '.json': 'application/json',
        '.png': 'image/png',
        '.jpg': 'image/jpeg',
        '.jpeg': 'image/jpeg',
        '.gif': 'image/gif',
        '.svg': 'image/svg+xml',
        '.ico': 'image/x-icon'
    };
    return mimeTypes[ext] || 'text/plain';
}

// Template management functions
async function scanDefaultTemplates() {
    try {
        const templates = {};
        const functionDirs = await fs.readdir(DEFAULT_TEMPLATES_DIR);
        
        for (const functionName of functionDirs) {
            const functionPath = path.join(DEFAULT_TEMPLATES_DIR, functionName);
            const stat = await fs.stat(functionPath);
            
            if (stat.isDirectory()) {
                const indexPath = path.join(functionPath, 'index.md');
                try {
                    const content = await fs.readFile(indexPath, 'utf8');
                    templates[functionName] = {
                        name: functionName,
                        content,
                        status: 'default',
                        source: 'built-in'
                    };
                } catch (err) {
                    console.log(`No index.md found for ${functionName}`);
                }
            }
        }
        
        return templates;
    } catch (err) {
        console.error('Error scanning default templates:', err);
        return {};
    }
}

async function scanCustomTemplates() {
    try {
        const templates = {};
        await fs.mkdir(TEMPLATES_DIR, { recursive: true });
        const functionDirs = await fs.readdir(TEMPLATES_DIR);
        
        for (const functionName of functionDirs) {
            const functionPath = path.join(TEMPLATES_DIR, functionName);
            const stat = await fs.stat(functionPath);
            
            if (stat.isDirectory()) {
                const indexPath = path.join(functionPath, 'index.md');
                try {
                    const content = await fs.readFile(indexPath, 'utf8');
                    templates[functionName] = {
                        name: functionName,
                        content,
                        status: 'custom',
                        source: 'user-custom'
                    };
                } catch (err) {
                    console.log(`No index.md found in custom templates for ${functionName}`);
                }
            }
        }
        
        return templates;
    } catch (err) {
        console.error('Error scanning custom templates:', err);
        return {};
    }
}

function getEnvironmentOverrides() {
    const overrides = {};
    
    for (const [key, value] of Object.entries(process.env)) {
        if (key.startsWith('MCP_PROMPT_')) {
            let functionName = key.replace('MCP_PROMPT_', '').toLowerCase();
            let isAppend = false;
            
            if (functionName.endsWith('_append')) {
                functionName = functionName.replace('_append', '');
                isAppend = true;
            }
            
            // Convert PLAN_TASK -> planTask format
            const camelCase = functionName.split('_').map((word, index) => 
                index === 0 ? word : word.charAt(0).toUpperCase() + word.slice(1)
            ).join('');
            
            if (!overrides[camelCase]) {
                overrides[camelCase] = {};
            }
            
            if (isAppend) {
                overrides[camelCase].append = value;
            } else {
                overrides[camelCase].override = value;
            }
        }
    }
    
    return overrides;
}

async function getAllTemplates() {
    const defaultTemplates = await scanDefaultTemplates();
    const customTemplates = await scanCustomTemplates();
    const envOverrides = getEnvironmentOverrides();
    
    const allTemplates = { ...defaultTemplates };
    
    // Apply custom templates
    for (const [name, template] of Object.entries(customTemplates)) {
        allTemplates[name] = template;
    }
    
    // Apply environment overrides
    for (const [name, override] of Object.entries(envOverrides)) {
        if (allTemplates[name]) {
            if (override.override) {
                allTemplates[name].content = override.override;
                allTemplates[name].status = 'env-override';
                allTemplates[name].source = 'environment';
            } else if (override.append) {
                allTemplates[name].content += '\n\n' + override.append;
                allTemplates[name].status = 'env-append';
                allTemplates[name].source = 'environment+' + allTemplates[name].source;
            }
        } else if (override.override) {
            // Create new template from environment
            allTemplates[name] = {
                name,
                content: override.override,
                status: 'env-only',
                source: 'environment'
            };
        }
    }
    
    return allTemplates;
}

async function getTemplate(functionName) {
    const templates = await getAllTemplates();
    return templates[functionName] || null;
}

async function saveCustomTemplate(functionName, content) {
    try {
        const functionDir = path.join(TEMPLATES_DIR, functionName);
        await fs.mkdir(functionDir, { recursive: true });
        
        const indexPath = path.join(functionDir, 'index.md');
        await fs.writeFile(indexPath, content, 'utf8');
        
        return true;
    } catch (err) {
        console.error('Error saving custom template:', err);
        return false;
    }
}

async function deleteCustomTemplate(functionName) {
    try {
        const functionDir = path.join(TEMPLATES_DIR, functionName);
        await fs.rm(functionDir, { recursive: true, force: true });
        return true;
    } catch (err) {
        console.error('Error deleting custom template:', err);
        return false;
    }
}


// Serve static files from dist directory
async function serveStaticFile(req, res, filePath) {
    try {
        const fullPath = path.join(__dirname, 'dist', filePath);
        const data = await fs.readFile(fullPath);
        const mimeType = getMimeType(fullPath);
        
        res.writeHead(200, { 
            'Content-Type': mimeType,
            'Cache-Control': 'public, max-age=31536000' // 1 year cache for assets
        });
        res.end(data);
    } catch (err) {
        // If file not found, serve index.html for SPA routing
        if (err.code === 'ENOENT' && !filePath.includes('.')) {
            try {
                const indexPath = path.join(__dirname, 'dist', 'index.html');
                const indexData = await fs.readFile(indexPath);
                res.writeHead(200, { 'Content-Type': 'text/html' });
                res.end(indexData);
            } catch (indexErr) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('React app not built. Run: npm run build');
            }
        } else {
            res.writeHead(404, { 'Content-Type': 'text/plain' });
            res.end('File not found');
        }
    }
}

// Initialize and start server
async function startServer() {
    projects = await loadSettings();
    
    const server = http.createServer(async (req, res) => {
        const url = new URL(req.url, `http://${req.headers.host}`);
        
        // Enable CORS
        res.setHeader('Access-Control-Allow-Origin', '*');
        res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
        res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
        
        if (req.method === 'OPTIONS') {
            res.writeHead(200);
            res.end();
            return;
        }
        
        // API routes
        if (url.pathname === '/api/check-env' && req.method === 'GET') {
            // Check for environment variable
            const envVarName = 'OPEN_AI_KEY_SHRIMP_TASK_VIEWER';
            const isSet = !!process.env[envVarName];
            console.log(`Checking env var ${envVarName}: ${isSet ? 'SET' : 'NOT SET'}`);
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify({ 
                envVarName,
                isSet,
                value: isSet ? '***HIDDEN***' : null 
            }));
            
        } else if (url.pathname === '/api/agents' && req.method === 'GET') {
            res.writeHead(200, { 'Content-Type': 'application/json' });
            res.end(JSON.stringify(projects));
            
        } else if (url.pathname === '/api/add-project' && req.method === 'POST') {
            // Handle JSON or form data
            let body = '';
            req.on('data', chunk => body += chunk.toString());
            req.on('end', async () => {
                try {
                    let name, taskFileContent, filePath, projectRoot;
                    
                    // Try to parse as JSON first
                    const contentType = req.headers['content-type'] || '';
                    if (contentType.includes('application/json')) {
                        const data = JSON.parse(body);
                        name = data.name;
                        taskFileContent = data.taskFile;
                        filePath = data.filePath;
                        projectRoot = data.projectRoot;
                    } else {
                        // Parse as URL-encoded form data
                        const formData = new URLSearchParams(body);
                        name = formData.get('name');
                        taskFileContent = formData.get('taskFile');
                        filePath = formData.get('filePath');
                        projectRoot = formData.get('projectRoot');
                    }
                    
                    if (!name) {
                        res.writeHead(400, { 'Content-Type': 'text/plain' });
                        res.end('Missing name');
                        return;
                    }
                    
                    // If a file path is provided, use it directly
                    if (filePath) {
                        const project = await addProject(name, filePath, projectRoot);
                        res.writeHead(200, { 'Content-Type': 'application/json' });
                        res.end(JSON.stringify(project));
                    } else if (taskFileContent) {
                        // Save the file content to a temporary location
                        const tempDir = path.join(os.tmpdir(), 'shrimp-task-viewer');
                        await fs.mkdir(tempDir, { recursive: true });
                        const tempFilePath = path.join(tempDir, `${Date.now()}-tasks.json`);
                        await fs.writeFile(tempFilePath, taskFileContent);
                        
                        const project = await addProject(name, tempFilePath, projectRoot);
                        res.writeHead(200, { 'Content-Type': 'application/json' });
                        res.end(JSON.stringify(project));
                    } else {
                        res.writeHead(400, { 'Content-Type': 'text/plain' });
                        res.end('Missing taskFile or filePath');
                    }
                } catch (err) {
                    res.writeHead(500, { 'Content-Type': 'text/plain' });
                    res.end('Internal server error: ' + err.message);
                }
            });
            
        } else if (url.pathname.startsWith('/api/remove-project/') && req.method === 'DELETE') {
            const projectId = url.pathname.split('/').pop();
            try {
                await removeProject(projectId);
                res.writeHead(200, { 'Content-Type': 'text/plain' });
                res.end('Project removed');
            } catch (err) {
                res.writeHead(500, { 'Content-Type': 'text/plain' });
                res.end('Internal server error: ' + err.message);
            }
            
        } else if (url.pathname.startsWith('/api/rename-project/') && req.method === 'PUT') {
            const projectId = url.pathname.split('/').pop();
            let body = '';
            req.on('data', chunk => body += chunk.toString());
            req.on('end', async () => {
                try {
                    const { name } = JSON.parse(body);
                    if (!name) {
                        res.writeHead(400, { 'Content-Type': 'text/plain' });
                        res.end('Missing name');
                        return;
                    }
                    const project = await renameProject(projectId, name);
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify(project));
                } catch (err) {
                    res.writeHead(500, { 'Content-Type': 'text/plain' });
                    res.end('Internal server error: ' + err.message);
                }
            });
            
        } else if (url.pathname.startsWith('/api/update-project/') && req.method === 'PUT') {
            const projectId = url.pathname.split('/').pop();
            let body = '';
            req.on('data', chunk => body += chunk.toString());
            req.on('end', async () => {
                try {
                    const updates = JSON.parse(body);
                    const project = await updateProject(projectId, updates);
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify(project));
                } catch (err) {
                    res.writeHead(500, { 'Content-Type': 'text/plain' });
                    res.end('Internal server error: ' + err.message);
                }
            });
            
        } else if (url.pathname.startsWith('/api/tasks/') && url.pathname.endsWith('/update') && req.method === 'PUT') {
            // Handle task update
            const pathParts = url.pathname.split('/');
            const projectId = pathParts[pathParts.length - 2];
            console.log('Update task route - projectId:', projectId, 'projects:', projects.map(p => p.id));
            const project = projects.find(p => p.id === projectId);
            
            if (!project) {
                console.error('Project not found:', projectId, 'Available projects:', projects.map(p => p.id));
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Project not found');
                return;
            }
            
            let body = '';
            req.on('data', chunk => body += chunk.toString());
            req.on('end', async () => {
                try {
                    const { taskId, updates } = JSON.parse(body);
                    
                    // Read current tasks
                    const data = await fs.readFile(project.path, 'utf8');
                    const tasksData = JSON.parse(data);
                    
                    // Find and update the task
                    const taskIndex = tasksData.tasks.findIndex(t => t.id === taskId);
                    if (taskIndex === -1) {
                        res.writeHead(404, { 'Content-Type': 'text/plain' });
                        res.end('Task not found');
                        return;
                    }
                    
                    // Update task fields
                    tasksData.tasks[taskIndex] = {
                        ...tasksData.tasks[taskIndex],
                        ...updates,
                        updatedAt: getLocalISOString()
                    };
                    
                    // Write back to file
                    await fs.writeFile(project.path, JSON.stringify(tasksData, null, 2));
                    
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify(tasksData.tasks[taskIndex]));
                } catch (err) {
                    console.error('Error updating task:', err);
                    res.writeHead(500, { 'Content-Type': 'text/plain' });
                    res.end('Error updating task: ' + err.message);
                }
            });
            
        } else if (url.pathname.startsWith('/api/tasks/') && url.pathname.endsWith('/delete') && req.method === 'DELETE') {
            // Handle task delete
            const pathParts = url.pathname.split('/');
            const taskId = pathParts[pathParts.length - 2];
            const projectId = pathParts[pathParts.length - 3];
            const project = projects.find(p => p.id === projectId);
            
            if (!project) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Project not found');
                return;
            }
            
            try {
                // Read current tasks
                const data = await fs.readFile(project.path, 'utf8');
                const tasksData = JSON.parse(data);
                
                // Find and remove the task
                const taskIndex = tasksData.tasks.findIndex(t => t.id === taskId);
                if (taskIndex === -1) {
                    res.writeHead(404, { 'Content-Type': 'text/plain' });
                    res.end('Task not found');
                    return;
                }
                
                // Remove the task
                tasksData.tasks.splice(taskIndex, 1);
                
                // Write back to file
                await fs.writeFile(project.path, JSON.stringify(tasksData, null, 2));
                
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ success: true, message: 'Task deleted successfully' }));
            } catch (err) {
                console.error('Error deleting task:', err);
                res.writeHead(500, { 'Content-Type': 'text/plain' });
                res.end('Error deleting task: ' + err.message);
            }
            
        } else if (url.pathname.startsWith('/api/tasks/')) {
            const projectId = url.pathname.split('?')[0].split('/').pop();
            const project = projects.find(p => p.id === projectId);
            
            if (!project) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Project not found');
                return;
            }
            
            try {
                console.log(`Reading tasks from: ${project.path}`);
                
                // Check if file exists
                try {
                    await fs.access(project.path);
                } catch (accessErr) {
                    // File doesn't exist - return empty tasks with helpful message
                    console.log(`Tasks file doesn't exist yet: ${project.path}`);
                    const emptyResponse = {
                        tasks: [],
                        projectRoot: project.projectRoot || null,
                        message: "No tasks found. The tasks.json file hasn't been created yet. Run shrimp in this folder to generate tasks."
                    };
                    res.writeHead(200, { 
                        'Content-Type': 'application/json',
                        'Cache-Control': 'no-store, no-cache, must-revalidate',
                        'Pragma': 'no-cache',
                        'Expires': '0'
                    });
                    res.end(JSON.stringify(emptyResponse));
                    return;
                }
                
                const stats = await fs.stat(project.path);
                console.log(`File last modified: ${stats.mtime}`);
                
                const data = await fs.readFile(project.path, 'utf8');
                const tasksData = JSON.parse(data);
                
                // Log task status for debugging
                const task880f = tasksData.tasks?.find(t => t.id === '880f4dd8-a603-4bb9-8d4d-5033887d0e0f');
                if (task880f) {
                    console.log(`Task 880f4dd8 status: ${task880f.status}`);
                }
                
                // Add projectRoot to the response
                if (project.projectRoot) {
                    tasksData.projectRoot = project.projectRoot;
                }
                
                res.writeHead(200, { 
                    'Content-Type': 'application/json',
                    'Cache-Control': 'no-store, no-cache, must-revalidate',
                    'Pragma': 'no-cache',
                    'Expires': '0'
                });
                res.end(JSON.stringify(tasksData));
            } catch (err) {
                console.error(`Error reading file ${project.path}:`, err);
                res.writeHead(500, { 'Content-Type': 'text/plain' });
                res.end('Error reading task file: ' + err.message);
            }
            
        } else if (url.pathname.startsWith('/api/history/') && url.pathname.split('/').length === 4) {
            const projectId = url.pathname.split('/').pop();
            const project = projects.find(p => p.id === projectId);
            
            if (!project) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Agent not found');
                return;
            }
            
            try {
                const tasksPath = project.path || project.filePath;
                const memoryDir = path.join(path.dirname(tasksPath), 'memory');
                
                console.log(`[History] Looking for memory directory at: ${memoryDir}`);
                console.log(`[History] Tasks path: ${tasksPath}`);
                
                // Check if memory directory exists
                const memoryExists = await fs.access(memoryDir).then(() => true).catch(() => false);
                if (!memoryExists) {
                    console.log(`[History] Memory directory does not exist at: ${memoryDir}`);
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ 
                        history: [],
                        message: `No history found. Memory directory expected at: ${memoryDir}`
                    }));
                    return;
                }
                
                // Read memory files
                const files = await fs.readdir(memoryDir);
                const memoryFiles = files.filter(f => f.startsWith('tasks_memory_') && f.endsWith('.json'));
                
                console.log(`[History] Found ${memoryFiles.length} memory files in ${memoryDir}`);
                
                const historyData = await Promise.all(memoryFiles.map(async (filename) => {
                    try {
                        const filePath = path.join(memoryDir, filename);
                        const content = await fs.readFile(filePath, 'utf8');
                        const data = JSON.parse(content);
                        
                        // Parse timestamp from filename: tasks_memory_2025-07-31T21-54-13.json
                        const timestampMatch = filename.match(/tasks_memory_(.+)\.json$/);
                        let timestamp = getLocalISOString();
                        if (timestampMatch) {
                            // Convert 2025-07-31T21-54-13 to 2025-07-31T21:54:13
                            const rawTimestamp = timestampMatch[1];
                            timestamp = rawTimestamp.replace(/T(\d{2})-(\d{2})-(\d{2})$/, 'T$1:$2:$3');
                        }
                        
                        // Calculate task statistics
                        const tasks = data.tasks || [];
                        const stats = {
                            total: tasks.length,
                            completed: tasks.filter(t => t.status === 'completed').length,
                            pending: tasks.filter(t => t.status === 'pending').length,
                            inProgress: tasks.filter(t => t.status === 'in_progress').length
                        };
                        
                        return {
                            filename,
                            timestamp,
                            taskCount: tasks.length,
                            stats,
                            hasData: tasks.length > 0
                        };
                    } catch (err) {
                        console.error(`Error reading memory file ${filename}:`, err);
                        return null;
                    }
                }));
                
                // Filter out failed files and sort by timestamp descending
                const validHistory = historyData.filter(h => h !== null)
                    .sort((a, b) => new Date(b.timestamp) - new Date(a.timestamp));
                
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({ history: validHistory }));
                
            } catch (err) {
                console.error('Error loading history:', err);
                res.writeHead(500, { 'Content-Type': 'text/plain' });
                res.end('Error loading history');
            }
            
        } else if (url.pathname.startsWith('/api/history/') && url.pathname.split('/').length === 5) {
            // Handle /api/history/{projectId}/{filename}
            const pathParts = url.pathname.split('/');
            const projectId = pathParts[3];
            const filename = pathParts[4];
            const project = projects.find(p => p.id === projectId);
            
            if (!project) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Agent not found');
                return;
            }
            
            // Security check: ensure filename is valid memory file
            if (!filename.startsWith('tasks_memory_') || !filename.endsWith('.json') || filename.includes('..')) {
                res.writeHead(400, { 'Content-Type': 'text/plain' });
                res.end('Invalid filename');
                return;
            }
            
            try {
                const tasksPath = project.path || project.filePath;
                const memoryDir = path.join(path.dirname(tasksPath), 'memory');
                const filePath = path.join(memoryDir, filename);
                
                // Check if file exists
                const fileExists = await fs.access(filePath).then(() => true).catch(() => false);
                if (!fileExists) {
                    res.writeHead(404, { 'Content-Type': 'text/plain' });
                    res.end('History file not found');
                    return;
                }
                
                // Read and parse the memory file
                const content = await fs.readFile(filePath, 'utf8');
                const data = JSON.parse(content);
                
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify(data));
                
            } catch (err) {
                console.error('Error loading history file:', err);
                if (err instanceof SyntaxError) {
                    res.writeHead(400, { 'Content-Type': 'text/plain' });
                    res.end('Invalid JSON in memory file');
                } else {
                    res.writeHead(500, { 'Content-Type': 'text/plain' });
                    res.end('Error loading history file');
                }
            }
            
        } else if (url.pathname === '/api/readme' && req.method === 'GET') {
            // Serve README.md file
            try {
                const readmePath = path.join(__dirname, 'README.md');
                const data = await fs.readFile(readmePath, 'utf8');
                res.writeHead(200, { 
                    'Content-Type': 'text/markdown; charset=utf-8',
                    'Cache-Control': 'no-cache, no-store, must-revalidate'
                });
                res.end(data);
            } catch (err) {
                console.error('Error reading README:', err);
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('README not found');
            }

        // Template management API routes
        } else if (url.pathname === '/api/templates' && req.method === 'GET') {
            // List all templates with status
            try {
                const templates = await getAllTemplates();
                const templateList = Object.values(templates).map(template => ({
                    name: template.name,
                    status: template.status,
                    source: template.source,
                    contentLength: template.content.length
                }));
                
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify(templateList));
            } catch (err) {
                res.writeHead(500, { 'Content-Type': 'text/plain' });
                res.end('Error loading templates: ' + err.message);
            }
            
        } else if (url.pathname.startsWith('/api/templates/') && !url.pathname.includes('/duplicate')) {
            const functionName = url.pathname.split('/').pop();
            
            if (req.method === 'GET') {
                // Get specific template
                try {
                    const template = await getTemplate(functionName);
                    if (!template) {
                        res.writeHead(404, { 'Content-Type': 'text/plain' });
                        res.end('Template not found');
                        return;
                    }
                    
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify(template));
                } catch (err) {
                    res.writeHead(500, { 'Content-Type': 'text/plain' });
                    res.end('Error loading template: ' + err.message);
                }
                
            } else if (req.method === 'PUT') {
                // Update template
                let body = '';
                req.on('data', chunk => body += chunk.toString());
                req.on('end', async () => {
                    try {
                        const { content } = JSON.parse(body);
                        if (!content) {
                            res.writeHead(400, { 'Content-Type': 'text/plain' });
                            res.end('Missing content');
                            return;
                        }
                        
                        const success = await saveCustomTemplate(functionName, content);
                        if (success) {
                            const updatedTemplate = await getTemplate(functionName);
                            res.writeHead(200, { 'Content-Type': 'application/json' });
                            res.end(JSON.stringify(updatedTemplate));
                        } else {
                            res.writeHead(500, { 'Content-Type': 'text/plain' });
                            res.end('Failed to save template');
                        }
                    } catch (err) {
                        res.writeHead(500, { 'Content-Type': 'text/plain' });
                        res.end('Error updating template: ' + err.message);
                    }
                });
                
            } else if (req.method === 'DELETE') {
                // Reset to default (delete custom template)
                try {
                    const success = await deleteCustomTemplate(functionName);
                    if (success) {
                        const defaultTemplate = await getTemplate(functionName);
                        res.writeHead(200, { 'Content-Type': 'application/json' });
                        res.end(JSON.stringify(defaultTemplate || { message: 'Template reset to default' }));
                    } else {
                        res.writeHead(500, { 'Content-Type': 'text/plain' });
                        res.end('Failed to reset template');
                    }
                } catch (err) {
                    res.writeHead(500, { 'Content-Type': 'text/plain' });
                    res.end('Error resetting template: ' + err.message);
                }
            }
            
        } else if (url.pathname.startsWith('/api/templates/') && url.pathname.endsWith('/duplicate') && req.method === 'POST') {
            // Duplicate template
            const functionName = url.pathname.split('/')[3];
            let body = '';
            req.on('data', chunk => body += chunk.toString());
            req.on('end', async () => {
                try {
                    const { newName } = JSON.parse(body);
                    if (!newName) {
                        res.writeHead(400, { 'Content-Type': 'text/plain' });
                        res.end('Missing newName');
                        return;
                    }
                    
                    const sourceTemplate = await getTemplate(functionName);
                    if (!sourceTemplate) {
                        res.writeHead(404, { 'Content-Type': 'text/plain' });
                        res.end('Source template not found');
                        return;
                    }
                    
                    const success = await saveCustomTemplate(newName, sourceTemplate.content);
                    if (success) {
                        const newTemplate = await getTemplate(newName);
                        res.writeHead(200, { 'Content-Type': 'application/json' });
                        res.end(JSON.stringify(newTemplate));
                    } else {
                        res.writeHead(500, { 'Content-Type': 'text/plain' });
                        res.end('Failed to duplicate template');
                    }
                } catch (err) {
                    res.writeHead(500, { 'Content-Type': 'text/plain' });
                    res.end('Error duplicating template: ' + err.message);
                }
            });
            
        // Global settings API routes
        } else if (url.pathname === '/api/global-settings' && req.method === 'GET') {
            // Get global settings
            try {
                const settings = await loadGlobalSettings();
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify(settings));
            } catch (err) {
                res.writeHead(500, { 'Content-Type': 'text/plain' });
                res.end('Error loading global settings: ' + err.message);
            }
            
        } else if (url.pathname === '/api/global-settings' && req.method === 'PUT') {
            // Update global settings
            let body = '';
            req.on('data', chunk => body += chunk.toString());
            req.on('end', async () => {
                try {
                    const newSettings = JSON.parse(body);
                    newSettings.lastUpdated = getLocalISOString();
                    newSettings.version = VERSION;
                    
                    await saveGlobalSettings(newSettings);
                    
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify(newSettings));
                } catch (err) {
                    res.writeHead(500, { 'Content-Type': 'text/plain' });
                    res.end('Error saving global settings: ' + err.message);
                }
            });
            
        // Agent management API routes
        } else if (url.pathname === '/api/agents/global' && req.method === 'GET') {
            // List global agents from Claude folder
            try {
                const settings = await loadGlobalSettings();
                const claudeFolderPath = settings.claudeFolderPath;
                
                if (!claudeFolderPath) {
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify([]));
                    return;
                }
                
                const agentsDir = path.join(claudeFolderPath, 'agents');
                let agentFiles = [];
                
                try {
                    const files = await fs.readdir(agentsDir);
                    agentFiles = files.filter(file => 
                        file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml')
                    );
                } catch (err) {
                    // Directory doesn't exist, return empty array
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify([]));
                    return;
                }
                
                // Read each agent file to get content
                const agentList = await Promise.all(agentFiles.map(async (filename) => {
                    try {
                        const filePath = path.join(agentsDir, filename);
                        const content = await fs.readFile(filePath, 'utf8');
                        const metadata = parseAgentMetadata(content);
                        return {
                            name: filename,
                            content: content,
                            path: filePath,
                            metadata: metadata
                        };
                    } catch (err) {
                        return {
                            name: filename,
                            content: '',
                            path: path.join(agentsDir, filename),
                            error: err.message,
                            metadata: parseAgentMetadata('')
                        };
                    }
                }));
                
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify(agentList));
            } catch (err) {
                res.writeHead(500, { 'Content-Type': 'text/plain' });
                res.end('Error loading global agents: ' + err.message);
            }
            
        } else if (url.pathname.startsWith('/api/agents/project/') && req.method === 'GET' && url.pathname.split('/').length === 5) {
            // List project agents from .claude/agents directory
            const pathParts = url.pathname.split('/');
            // /api/agents/project/:projectId
            const projectId = pathParts[4];
            console.log('Looking for project agents for projectId:', projectId);
            console.log('Available projects:', projects.map(p => ({ id: p.id, name: p.name, projectRoot: p.projectRoot })));
            const project = projects.find(p => p.id === projectId);
            
            if (!project) {
                console.log('Project not found for projectId:', projectId);
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Project not found');
                return;
            }
            
            try {
                const projectRoot = project.projectRoot;
                console.log('Project root:', projectRoot);
                if (!projectRoot) {
                    console.log('No project root configured for project:', projectId);
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify([]));
                    return;
                }
                
                const agentsDir = path.join(projectRoot, '.claude', 'agents');
                console.log('Looking for agents in directory:', agentsDir);
                let agentFiles = [];
                
                try {
                    const files = await fs.readdir(agentsDir);
                    console.log('Found files in agents directory:', files);
                    agentFiles = files.filter(file => 
                        file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml')
                    );
                    console.log('Filtered agent files:', agentFiles);
                } catch (err) {
                    // Directory doesn't exist, return empty array
                    console.log('Error reading agents directory:', err.message);
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify([]));
                    return;
                }
                
                // Read each agent file to get content
                const projectAgents = await Promise.all(agentFiles.map(async (filename) => {
                    try {
                        const filePath = path.join(agentsDir, filename);
                        const content = await fs.readFile(filePath, 'utf8');
                        const metadata = parseAgentMetadata(content);
                        // Debug logging for project agents
                        console.log(`Parsing ${filename}:`, {
                            tools: metadata.tools,
                            toolsLength: metadata.tools.length,
                            firstLine: content.split('\n')[0]
                        });
                        return {
                            name: filename,
                            content: content,
                            path: filePath,
                            metadata: metadata
                        };
                    } catch (err) {
                        return {
                            name: filename,
                            content: '',
                            path: path.join(agentsDir, filename),
                            error: err.message,
                            metadata: parseAgentMetadata('')
                        };
                    }
                }));
                
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify(projectAgents));
            } catch (err) {
                res.writeHead(500, { 'Content-Type': 'text/plain' });
                res.end('Error loading project agents: ' + err.message);
            }
            
        } else if (url.pathname.startsWith('/api/agents/global/') && req.method === 'GET') {
            // Read specific global agent file
            const filename = url.pathname.split('/').pop();
            
            try {
                const settings = await loadGlobalSettings();
                const claudeFolderPath = settings.claudeFolderPath;
                
                if (!claudeFolderPath) {
                    res.writeHead(404, { 'Content-Type': 'text/plain' });
                    res.end('Claude folder path not configured');
                    return;
                }
                
                const filePath = path.join(claudeFolderPath, 'agents', filename);
                const content = await fs.readFile(filePath, 'utf8');
                
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({
                    name: filename,
                    content: content,
                    path: filePath,
                    metadata: parseAgentMetadata(content)
                }));
            } catch (err) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Agent file not found: ' + err.message);
            }
            
        } else if (url.pathname.startsWith('/api/agents/global/') && req.method === 'PUT') {
            // Update specific global agent file
            const filename = url.pathname.split('/').pop();
            let body = '';
            req.on('data', chunk => body += chunk.toString());
            req.on('end', async () => {
                try {
                    const { content } = JSON.parse(body);
                    if (!content && content !== '') {
                        res.writeHead(400, { 'Content-Type': 'text/plain' });
                        res.end('Missing content');
                        return;
                    }
                    
                    const settings = await loadGlobalSettings();
                    const claudeFolderPath = settings.claudeFolderPath;
                    
                    if (!claudeFolderPath) {
                        res.writeHead(404, { 'Content-Type': 'text/plain' });
                        res.end('Claude folder path not configured');
                        return;
                    }
                    
                    const filePath = path.join(claudeFolderPath, 'agents', filename);
                    await fs.writeFile(filePath, content, 'utf8');
                    
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({
                        name: filename,
                        content: content,
                        path: filePath,
                        message: 'Agent updated successfully'
                    }));
                } catch (err) {
                    res.writeHead(500, { 'Content-Type': 'text/plain' });
                    res.end('Error updating agent: ' + err.message);
                }
            });
            
        } else if (url.pathname.startsWith('/api/agents/project/') && req.method === 'GET' && url.pathname.split('/').length === 6) {
            // Read specific project agent file
            const pathParts = url.pathname.split('/');
            const projectId = pathParts[4];
            const filename = pathParts[5];
            const project = projects.find(p => p.id === projectId);
            
            if (!project) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Project not found');
                return;
            }
            
            try {
                const projectRoot = project.projectRoot;
                if (!projectRoot) {
                    res.writeHead(404, { 'Content-Type': 'text/plain' });
                    res.end('Project root not configured for this profile');
                    return;
                }
                
                const filePath = path.join(projectRoot, '.claude', 'agents', filename);
                const content = await fs.readFile(filePath, 'utf8');
                
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify({
                    name: filename,
                    content: content,
                    path: filePath,
                    metadata: parseAgentMetadata(content)
                }));
            } catch (err) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Agent file not found: ' + err.message);
            }
            
        } else if (url.pathname.startsWith('/api/agents/project/') && req.method === 'PUT' && url.pathname.split('/').length === 6) {
            // Update specific project agent file
            const pathParts = url.pathname.split('/');
            const projectId = pathParts[4];
            const filename = pathParts[5];
            const project = projects.find(p => p.id === projectId);
            
            if (!project) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Project not found');
                return;
            }
            
            let body = '';
            req.on('data', chunk => body += chunk.toString());
            req.on('end', async () => {
                try {
                    const { content } = JSON.parse(body);
                    if (!content && content !== '') {
                        res.writeHead(400, { 'Content-Type': 'text/plain' });
                        res.end('Missing content');
                        return;
                    }
                    
                    const projectRoot = project.projectRoot;
                    if (!projectRoot) {
                        res.writeHead(404, { 'Content-Type': 'text/plain' });
                        res.end('Project root not configured for this profile');
                        return;
                    }
                    
                    const filePath = path.join(projectRoot, '.claude', 'agents', filename);
                    await fs.writeFile(filePath, content, 'utf8');
                    
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({
                        name: filename,
                        content: content,
                        path: filePath,
                        message: 'Project agent updated successfully'
                    }));
                } catch (err) {
                    res.writeHead(500, { 'Content-Type': 'text/plain' });
                    res.end('Error updating project agent: ' + err.message);
                }
            });
            
        } else if (url.pathname.startsWith('/api/agents/combined/') && req.method === 'GET') {
            // Get combined list of global and project agents
            const profileId = url.pathname.split('/').pop();
            const project = projects.find(p => p.id === profileId);
            
            if (!project) {
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Project not found');
                return;
            }
            
            try {
                // Load global agents
                const settings = await loadGlobalSettings();
                const claudeFolderPath = settings.claudeFolderPath;
                let globalAgents = [];
                
                if (claudeFolderPath) {
                    const agentsDir = path.join(claudeFolderPath, 'agents');
                    try {
                        const files = await fs.readdir(agentsDir);
                        const agentFiles = files.filter(file => 
                            file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml')
                        );
                        
                        globalAgents = await Promise.all(agentFiles.map(async (filename) => {
                            try {
                                const filePath = path.join(agentsDir, filename);
                                const content = await fs.readFile(filePath, 'utf8');
                                const metadata = parseAgentMetadata(content);
                                return {
                                    name: filename,
                                    type: 'global',
                                    content: content,
                                    path: filePath,
                                    metadata: metadata
                                };
                            } catch (err) {
                                return {
                                    name: filename,
                                    type: 'global',
                                    content: '',
                                    path: path.join(agentsDir, filename),
                                    error: err.message,
                                    metadata: parseAgentMetadata('')
                                };
                            }
                        }));
                    } catch (err) {
                        // Directory doesn't exist, continue with empty global agents
                        console.log('Global agents directory not found:', err.message);
                    }
                }
                
                // Load project agents
                let projectAgents = [];
                const projectRoot = project.projectRoot;
                
                if (projectRoot) {
                    const agentsDir = path.join(projectRoot, '.claude', 'agents');
                    try {
                        const files = await fs.readdir(agentsDir);
                        const agentFiles = files.filter(file => 
                            file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml')
                        );
                        
                        projectAgents = await Promise.all(agentFiles.map(async (filename) => {
                            try {
                                const filePath = path.join(agentsDir, filename);
                                const content = await fs.readFile(filePath, 'utf8');
                                const metadata = parseAgentMetadata(content);
                                return {
                                    name: filename,
                                    type: 'project',
                                    content: content,
                                    path: filePath,
                                    metadata: metadata
                                };
                            } catch (err) {
                                return {
                                    name: filename,
                                    type: 'project',
                                    content: '',
                                    path: path.join(agentsDir, filename),
                                    error: err.message,
                                    metadata: parseAgentMetadata('')
                                };
                            }
                        }));
                    } catch (err) {
                        // Directory doesn't exist, continue with empty project agents
                        console.log('Project agents directory not found:', err.message);
                    }
                }
                
                // Combine and deduplicate agents
                // Project agents take precedence over global agents with the same name
                const agentMap = new Map();
                
                // Add global agents first
                globalAgents.forEach(agent => {
                    agentMap.set(agent.name, agent);
                });
                
                // Add/override with project agents
                projectAgents.forEach(agent => {
                    agentMap.set(agent.name, agent);
                });
                
                // Convert map back to array and return agent objects with metadata
                const combinedAgents = Array.from(agentMap.values()).map(agent => ({
                    name: agent.name,
                    description: agent.metadata?.description || '',
                    type: agent.type,
                    tools: agent.metadata?.tools || [],
                    color: agent.metadata?.color || null
                }));
                
                res.writeHead(200, { 'Content-Type': 'application/json' });
                res.end(JSON.stringify(combinedAgents));
                
            } catch (err) {
                console.error('Error loading combined agents:', err);
                res.writeHead(500, { 'Content-Type': 'text/plain' });
                res.end('Error loading combined agents: ' + err.message);
            }
            
        } else if (url.pathname.startsWith('/releases/')) {
            // Serve release files (markdown and images)
            const fileName = url.pathname.split('/').pop();
            try {
                const releasePath = path.join(__dirname, 'releases', fileName);
                console.log('Attempting to read release file:', releasePath);
                
                if (fileName.endsWith('.md')) {
                    const data = await fs.readFile(releasePath, 'utf8');
                    res.writeHead(200, { 
                        'Content-Type': 'text/markdown; charset=utf-8',
                        'Cache-Control': 'no-cache, no-store, must-revalidate'
                    });
                    res.end(data);
                } else {
                    // Serve images and other files
                    const data = await fs.readFile(releasePath);
                    const mimeType = getMimeType(releasePath);
                    res.writeHead(200, { 
                        'Content-Type': mimeType,
                        'Cache-Control': 'public, max-age=31536000' // Cache images for 1 year
                    });
                    res.end(data);
                }
            } catch (err) {
                console.error('Error reading release file:', err);
                res.writeHead(404, { 'Content-Type': 'text/plain' });
                res.end('Release file not found');
            }
            
        } else if (url.pathname === '/api/ai-assign-agents' && req.method === 'POST') {
            // AI-powered agent assignment for bulk tasks
            let body = '';
            req.on('data', chunk => body += chunk.toString());
            req.on('end', async () => {
                try {
                    const { projectId, taskIds } = JSON.parse(body);
                    console.log('AI Agent Assignment request:', { projectId, taskIds });
                    
                    // Check if OpenAI API key is set - first from settings, then environment
                    let openAIKey = process.env.OPENAI_API_KEY || process.env.OPEN_AI_KEY_SHRIMP_TASK_VIEWER;
                    
                    // Try to get key from global settings if not in environment
                    if (!openAIKey) {
                        try {
                            const globalSettings = await loadGlobalSettings();
                            if (globalSettings && globalSettings.openAIKey) {
                                openAIKey = globalSettings.openAIKey;
                            }
                        } catch (err) {
                            console.error('Error loading global settings for API key:', err);
                        }
                    }
                    
                    if (!openAIKey) {
                        res.writeHead(400, { 'Content-Type': 'application/json' });
                        res.end(JSON.stringify({
                            error: 'OpenAI API key not configured',
                            message: 'To use AI agent assignment, please configure your OpenAI API key.',
                            instructions: [
                                '1. Go to Settings → Global Settings in the app',
                                '   Enter your API key in the "OpenAI API Key" field',
                                '   Click Save',
                                '',
                                '2. Or create a .env file in:',
                                '   ' + path.resolve(process.cwd(), '.env'),
                                '   Add: OPENAI_API_KEY=sk-your-api-key-here',
                                '',
                                '3. Get your API key from:',
                                '   https://platform.openai.com/api-keys'
                            ]
                        }));
                        return;
                    }
                    
                    // Get project and tasks
                    const project = projects.find(p => p.id === projectId);
                    if (!project) {
                        res.writeHead(404, { 'Content-Type': 'application/json' });
                        res.end(JSON.stringify({ error: 'Project not found' }));
                        return;
                    }
                    
                    // Load tasks
                    const tasksData = await fs.readFile(project.path || project.filePath, 'utf8');
                    const tasksJson = JSON.parse(tasksData);
                    const allTasks = Array.isArray(tasksJson) ? tasksJson : (tasksJson.tasks || []);
                    const selectedTasks = allTasks.filter(task => taskIds.includes(task.id));
                    
                    if (selectedTasks.length === 0) {
                        res.writeHead(400, { 'Content-Type': 'application/json' });
                        res.end(JSON.stringify({ error: 'No valid tasks found' }));
                        return;
                    }
                    
                    // Get available agents using internal method
                    let availableAgents = [];
                    try {
                        // Get global agents
                        const settings = await loadGlobalSettings();
                        const claudeFolderPath = settings.claudeFolderPath;
                        let globalAgents = [];
                        
                        if (claudeFolderPath) {
                            const agentsDir = path.join(claudeFolderPath, 'agents');
                            try {
                                const files = await fs.readdir(agentsDir);
                                const agentFiles = files.filter(file => 
                                    file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml')
                                );
                                
                                globalAgents = await Promise.all(agentFiles.map(async (filename) => {
                                    try {
                                        const filePath = path.join(agentsDir, filename);
                                        const content = await fs.readFile(filePath, 'utf8');
                                        const metadata = parseAgentMetadata(content);
                                        return {
                                            name: filename,
                                            type: 'global',
                                            content: content,
                                            path: filePath,
                                            metadata: metadata
                                        };
                                    } catch (err) {
                                        return null;
                                    }
                                }));
                                globalAgents = globalAgents.filter(a => a !== null);
                            } catch (err) {
                                console.log('Global agents directory not found:', err.message);
                            }
                        }
                        
                        // Get project agents
                        let projectAgents = [];
                        if (project.projectRoot) {
                            const agentsDir = path.join(project.projectRoot, '.claude', 'agents');
                            try {
                                const files = await fs.readdir(agentsDir);
                                const agentFiles = files.filter(file => 
                                    file.endsWith('.md') || file.endsWith('.yaml') || file.endsWith('.yml')
                                );
                                
                                projectAgents = await Promise.all(agentFiles.map(async (filename) => {
                                    try {
                                        const filePath = path.join(agentsDir, filename);
                                        const content = await fs.readFile(filePath, 'utf8');
                                        const metadata = parseAgentMetadata(content);
                                        return {
                                            name: filename,
                                            type: 'project',
                                            content: content,
                                            path: filePath,
                                            metadata: metadata
                                        };
                                    } catch (err) {
                                        return null;
                                    }
                                }));
                                projectAgents = projectAgents.filter(a => a !== null);
                            } catch (err) {
                                console.log('Project agents directory not found:', err.message);
                            }
                        }
                        
                        // Combine agents
                        const agentMap = new Map();
                        globalAgents.forEach(agent => agentMap.set(agent.name, agent));
                        projectAgents.forEach(agent => agentMap.set(agent.name, agent));
                        availableAgents = Array.from(agentMap.values());
                    } catch (err) {
                        console.error('Error loading agents:', err);
                        availableAgents = [];
                    }
                    
                    // Prepare the prompt for OpenAI
                    const agentsList = availableAgents.map(agent => {
                        const desc = agent.metadata?.description || agent.content?.slice(0, 200) || 'No description';
                        return '- ' + agent.name + ': ' + desc;
                    }).join('\n');
                    
                    const tasksList = selectedTasks.map(task => {
                        return '- Task ID: ' + task.id + '\n  Name: ' + task.name + '\n  Description: ' + (task.description || 'No description') + '\n  Dependencies: ' + (task.dependencies?.join(', ') || 'None');
                    }).join('\n\n');
                    
                    const prompt = 'You are an AI assistant helping to assign specialized agents to tasks.\n\nAvailable Agents:\n' + agentsList + '\n\nTasks to Assign:\n' + tasksList + '\n\nFor each task, select the most appropriate agent based on the task requirements and agent capabilities. If no agent is particularly suitable, you may assign "No agent".\n\nReturn ONLY a JSON object mapping task IDs to agent names, like this:\n{\n  "task-id-1": "agent-name.md",\n  "task-id-2": "No agent",\n  "task-id-3": "another-agent.yaml"\n}';

                    // Call OpenAI API using https module
                    
                    const openAIData = JSON.stringify({
                        model: 'gpt-4',
                        messages: [
                            {
                                role: 'system',
                                content: 'You are a helpful assistant that assigns agents to tasks based on their descriptions and capabilities. Always respond with valid JSON only.'
                            },
                            {
                                role: 'user',
                                content: prompt
                            }
                        ],
                        temperature: 0.3,
                        max_tokens: 1000
                    });
                    
                    const openAIPromise = new Promise((resolve, reject) => {
                        const options = {
                            hostname: 'api.openai.com',
                            path: '/v1/chat/completions',
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json',
                                'Authorization': `Bearer ${openAIKey}`,
                                'Content-Length': Buffer.byteLength(openAIData)
                            }
                        };
                        
                        const req = https.request(options, (res) => {
                            let data = '';
                            res.on('data', chunk => data += chunk);
                            res.on('end', () => {
                                if (res.statusCode === 200) {
                                    try {
                                        resolve(JSON.parse(data));
                                    } catch (err) {
                                        reject(new Error('Invalid JSON from OpenAI'));
                                    }
                                } else {
                                    reject(new Error('OpenAI API error: ' + res.statusCode + ' - ' + data));
                                }
                            });
                        });
                        
                        req.on('error', reject);
                        req.write(openAIData);
                        req.end();
                    });
                    
                    try {
                        const aiResult = await openAIPromise;
                        const assignments = JSON.parse(aiResult.choices[0].message.content);
                        
                        // Update tasks with AI assignments
                        let updatedCount = 0;
                        allTasks.forEach(task => {
                            if (assignments[task.id] !== undefined) {
                                const agentName = assignments[task.id];
                                if (agentName === 'No agent' || agentName === null) {
                                    delete task.agent;
                                } else {
                                    task.agent = agentName;
                                }
                                updatedCount++;
                            }
                        });
                        
                        // Save updated tasks maintaining original structure
                        const dataToSave = Array.isArray(tasksJson) ? allTasks : { ...tasksJson, tasks: allTasks };
                        await fs.writeFile(project.path || project.filePath, JSON.stringify(dataToSave, null, 2));
                        
                        res.writeHead(200, { 'Content-Type': 'application/json' });
                        res.end(JSON.stringify({ 
                            success: true,
                            updatedCount,
                            assignments
                        }));
                        
                    } catch (err) {
                        console.error('Error in AI agent assignment:', err);
                        res.writeHead(500, { 'Content-Type': 'application/json' });
                        res.end(JSON.stringify({ 
                            error: 'Failed to assign agents',
                            details: err.message 
                        }));
                    }
                } catch (err) {
                    console.error('Error processing AI assignment request:', err);
                    res.writeHead(500, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ error: 'Internal server error' }));
                }
            });
            
        } else if (url.pathname === '/api/chat' && req.method === 'POST') {
            // Handle chat with AI agents
            let body = '';
            req.on('data', chunk => body += chunk.toString());
            req.on('end', async () => {
                try {
                    const { message, agents, context, profileId, openAIKey, availableAgents } = JSON.parse(body);
                    console.log('Chat request:', { message, agents, context: context?.currentPage });
                    
                    // Validate OpenAI key
                    const apiKey = openAIKey || process.env.OPENAI_API_KEY || process.env.OPEN_AI_KEY_SHRIMP_TASK_VIEWER;
                    
                    if (!apiKey) {
                        res.writeHead(400, { 'Content-Type': 'application/json' });
                        res.end(JSON.stringify({
                            error: 'OpenAI API key not configured',
                            message: 'Please configure your OpenAI API key in Settings → Global Settings'
                        }));
                        return;
                    }
                    
                    // Build context-aware prompt
                    let systemPrompt = 'You are an AI assistant helping with task management in the Shrimp Task Manager. You have access to information about available agents and can help users understand tasks, suggest agent assignments, and provide task-related insights.\n\n';
                    
                    // Add available agents
                    systemPrompt += 'Available agents for this project:\n';
                    systemPrompt += availableAgents.map(a => '- ' + a.name + ': ' + (a.description || 'No description')).join('\n');
                    systemPrompt += '\n\n';
                    
                    // Add current context
                    systemPrompt += 'Current context:\n- Page: ' + context.currentPage + '\n';
                    
                    // Add current task details if available
                    if (context.currentTask) {
                        systemPrompt += 'Current Task Details:\n';
                        systemPrompt += '- Name: ' + context.currentTask.name + '\n';
                        systemPrompt += '- Status: ' + context.currentTask.status + '\n';
                        systemPrompt += '- Description: ' + (context.currentTask.description || 'No description') + '\n';
                        systemPrompt += '- Assigned Agent: ' + (context.currentTask.assignedAgent || 'Unassigned') + '\n';
                        systemPrompt += '- Dependencies: ' + (context.currentTask.dependencies?.join(', ') || 'None') + '\n';
                    }
                    
                    // Add tasks summary
                    if (context.tasksSummary) {
                        systemPrompt += '\nTasks Overview:\n';
                        systemPrompt += '- Total tasks: ' + context.tasksSummary.total + '\n';
                        systemPrompt += '- Completed: ' + context.tasksSummary.completed + '\n';
                        systemPrompt += '- In Progress: ' + context.tasksSummary.inProgress + '\n';
                        systemPrompt += '- Pending: ' + context.tasksSummary.pending + '\n';
                    }
                    
                    // Add completed tasks
                    if (context.completedTasks && context.completedTasks.length > 0) {
                        systemPrompt += '\nCompleted Tasks:\n';
                        systemPrompt += context.completedTasks.map(t => '- ' + t.name + (t.description ? ': ' + t.description : '')).join('\n');
                        systemPrompt += '\n';
                    }
                    
                    // Add in progress tasks
                    if (context.inProgressTasks && context.inProgressTasks.length > 0) {
                        systemPrompt += '\nIn Progress Tasks:\n';
                        systemPrompt += context.inProgressTasks.map(t => '- ' + t.name + (t.description ? ': ' + t.description : '')).join('\n');
                        systemPrompt += '\n';
                    }
                    
                    // Add pending tasks
                    if (context.pendingTasks && context.pendingTasks.length > 0) {
                        systemPrompt += '\nPending Tasks:\n';
                        systemPrompt += context.pendingTasks.map(t => '- ' + t.name + (t.description ? ': ' + t.description : '')).join('\n');
                        systemPrompt += '\n';
                    }
                    
                    // Add available agents details
                    if (context.availableAgents && context.availableAgents.length > 0) {
                        systemPrompt += '\nAvailable Agents:\n';
                        systemPrompt += context.availableAgents.map(a => '- ' + a.name + ' (' + a.type + '): ' + a.description + (a.tools && a.tools.length > 0 ? ' | Tools: ' + a.tools.join(', ') : '')).join('\n');
                        systemPrompt += '\n';
                    }
                    
                    // Add agent assignments
                    if (context.agentAssignments && Object.keys(context.agentAssignments).length > 0) {
                        systemPrompt += '\nAgent Assignment Statistics:\n';
                        systemPrompt += Object.entries(context.agentAssignments).map(([agent, stats]) => 
                            '- ' + agent + ': ' + stats.total + ' tasks (' + stats.completed + ' completed, ' + stats.inProgress + ' in progress, ' + stats.pending + ' pending)'
                        ).join('\n');
                        systemPrompt += '\n';
                    }
                    
                    // Add unassigned tasks
                    if (context.unassignedTasks && context.unassignedTasks.total > 0) {
                        systemPrompt += '\nUnassigned Tasks: ' + context.unassignedTasks.total + ' total (' + context.unassignedTasks.completed + ' completed, ' + context.unassignedTasks.inProgress + ' in progress, ' + context.unassignedTasks.pending + ' pending)\n';
                    }
                    
                    systemPrompt += '\nWhen the user asks for summaries or information about tasks, use the detailed task information provided in the context.\n';
                    systemPrompt += 'When suggesting agent assignments, consider the agent\'s capabilities and the task requirements.\n\n';
                    systemPrompt += 'IMPORTANT: If the user asks to modify/edit a task and there is a currentTask in the context, respond with the modification in this EXACT format:\n';
                    systemPrompt += 'TASK_MODIFICATION: {JSON object with the fields to update}\n\n';
                    systemPrompt += 'Available task fields you can modify:\n';
                    systemPrompt += '- name: The task title/name\n';
                    systemPrompt += '- description: The task description\n';
                    systemPrompt += '- notes: Additional notes about the task\n';
                    systemPrompt += '- status: Task status (pending, in_progress, completed)\n';
                    systemPrompt += '- assignedAgent: Which agent is assigned to the task\n';
                    systemPrompt += '- implementationGuide: Implementation guidance\n';
                    systemPrompt += '- verificationCriteria: How to verify completion\n';
                    systemPrompt += '- dependencies: Task dependencies (array)\n';
                    systemPrompt += '- relatedFiles: Related files (array)\n\n';
                    systemPrompt += 'Examples:\n';
                    systemPrompt += 'TASK_MODIFICATION: {"notes": "Updated notes with hello world"}\n';
                    systemPrompt += 'TASK_MODIFICATION: {"description": "New description", "status": "in_progress"}\n';
                    systemPrompt += 'TASK_MODIFICATION: {"assignedAgent": "gpt-engineer"}\n\n';
                    systemPrompt += 'Be helpful, concise, and specific in your responses.\n\n';
                    systemPrompt += 'FORMATTING: Use markdown formatting and emojis to make your responses more readable:\n';
                    systemPrompt += '- Use **bold** for important points\n';
                    systemPrompt += '- Use \'code\' for technical terms\n';
                    systemPrompt += '- Use ✅ for completed/positive items in lists\n';
                    systemPrompt += '- Use ❌ for failed/negative items in lists\n';
                    systemPrompt += '- Use emojis (📋 📝 ⚠️ 🔧 💡 🎯) to add visual context\n';
                    systemPrompt += '- Use headers (##) for section organization\n';

                    // Call OpenAI API
                    const openAIData = JSON.stringify({
                        model: 'gpt-4-turbo-preview',
                        messages: [
                            { role: 'system', content: systemPrompt },
                            { role: 'user', content: message }
                        ],
                        temperature: 0.7,
                        max_tokens: 1000
                    });
                    
                    const openAIResponse = await new Promise((resolve, reject) => {
                        const options = {
                            hostname: 'api.openai.com',
                            path: '/v1/chat/completions',
                            method: 'POST',
                            headers: {
                                'Content-Type': 'application/json',
                                'Authorization': 'Bearer ' + apiKey,
                                'Content-Length': Buffer.byteLength(openAIData)
                            }
                        };
                        
                        const req = https.request(options, (res) => {
                            let data = '';
                            res.on('data', chunk => data += chunk);
                            res.on('end', () => {
                                if (res.statusCode === 200) {
                                    try {
                                        resolve(JSON.parse(data));
                                    } catch (err) {
                                        reject(new Error('Invalid JSON from OpenAI'));
                                    }
                                } else {
                                    reject(new Error('OpenAI API error: ' + res.statusCode + ' - ' + data));
                                }
                            });
                        });
                        
                        req.on('error', reject);
                        req.write(openAIData);
                        req.end();
                    });
                    
                    let aiResponse = openAIResponse.choices[0].message.content;
                    
                    // Check if response suggests task modification
                    let taskModification = null;
                    if (context.currentTask && aiResponse.includes('TASK_MODIFICATION:')) {
                        try {
                            // Extract the JSON from the response
                            const modificationMatch = aiResponse.match(/TASK_MODIFICATION:\s*(\{[^}]+\})/);
                            if (modificationMatch) {
                                const modifications = JSON.parse(modificationMatch[1]);
                                taskModification = {
                                    suggested: true,
                                    ...modifications
                                };
                                console.log('Parsed task modification:', taskModification);
                                
                                // Remove the TASK_MODIFICATION line from the response
                                aiResponse = aiResponse.replace(/TASK_MODIFICATION:\s*\{[^}]+\}\s*/, '').trim();
                            }
                        } catch (err) {
                            console.error('Error parsing task modification:', err);
                        }
                    }
                    
                    res.writeHead(200, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({
                        response: aiResponse,
                        respondingAgents: agents,
                        taskModification
                    }));
                    
                } catch (err) {
                    console.error('Error processing chat request:', err);
                    res.writeHead(500, { 'Content-Type': 'application/json' });
                    res.end(JSON.stringify({ 
                        error: 'Failed to process chat request',
                        details: err.message 
                    }));
                }
            });
            
        } else {
            // Serve static files (React app)
            const filePath = url.pathname === '/' ? 'index.html' : url.pathname.slice(1);
            await serveStaticFile(req, res, filePath);
        }
    });

    server.listen(PORT, '127.0.0.1', () => {
        console.log(`\n🦐 Shrimp Task Manager Viewer Server v${VERSION}`);
        console.log('===============================================');
        console.log(`Server is running at: http://localhost:${PORT}`);
        console.log(`Also accessible at: http://127.0.0.1:${PORT}`);
        console.log(`\nSettings file: ${SETTINGS_FILE}`);
        console.log('    ');
        console.log('Available projects:');
        if (projects.length === 0) {
            console.log('  - No projects configured. Add projects via the web interface.');
        } else {
            projects.forEach(project => {
                console.log(`  - ${project.name} (${project.path})`);
            });
        }
        console.log('\n🎯 Features:');
        console.log('  • React-based UI with TanStack Table');
        console.log('  • Real-time search and filtering');
        console.log('  • Sortable columns with pagination');
        console.log('  • Auto-refresh functionality');
        console.log('  • Profile management via web interface');
        console.log('\nOpen your browser to view tasks!');
    });

    return server;
}

// Start the server
startServer().catch(err => {
    console.error('Failed to start server:', err);
    process.exit(1);
});

export { startServer };